﻿using System;
using System.Linq;
using System.Web.Mvc;
using System.Web.Security;
using SnippetBox.Core.Common.Mvc.Attributes;
using SnippetBox.Core.Common.Paging;
using SnippetBox.Core.Common.Paging.Simple;
using SnippetBox.Core.Common.Security;
using SnippetBox.Core.Data.Models;
using SnippetBox.Core.Data.Service;
using SnippetBox.Core.Common.Extensions;
using SnippetBox.Core.Infrastructure;
using SnippetBox.Web.Models;

namespace SnippetBox.Web.Controllers {
    public class UserController : Controller {
        private readonly UserService _userService = new UserService();
        private const int PAGE_SIZE = 10;

        [ImportModelStateFromTempData]
        public ActionResult Login() {
            string username = TempData["Username"] != null ? TempData["Username"].ToString() : null;

            if (Request.IsAjaxRequest())
                return PartialView(new LoginModel(username));
            
            return View(new LoginModel(username));
        }

        [HttpPost, ValidateAntiForgeryToken]
        public ActionResult Login(LoginModel loginModel, string returnUrl) {
            TempData["Username"] = loginModel.Username;

            if (!ModelState.IsValid)
                return RedirectToAction("Login", "User", new { area = "" });

            var user = _userService.GetByUsername(loginModel.Username);

            if (user == null)
                return RedirectToLoginWithError();

            if (Hash.Make(loginModel.Password) != user.PasswordHashed)
                return RedirectToLoginWithError();

            FormsAuthentication.SetAuthCookie(user.Username, true);
            Session["User"] = user;

            return Redirect(returnUrl ?? "/");
        }

        [ImportModelStateFromTempData]
        public ActionResult Register() {
            if (!Settings.Current.Permissions.AllowRegistration)
                return Redirect(FormsAuthentication.LoginUrl);

            return View();
        }
        
        [HttpPost, ValidateAntiForgeryToken]
        public ActionResult Register(RegisterModel registerModel) {
            if (!Settings.Current.Permissions.AllowRegistration)
                return Redirect(FormsAuthentication.LoginUrl);

            if (!ModelState.IsValid)
                return RedirectToAction("Register", "User");
            
            User user = new User(registerModel.Username, Hash.Make(registerModel.Password));
            user.Email = registerModel.Email;

            // Create user in database
            _userService.Create(user);
            _userService.Save();

            // Auto-login user
            FormsAuthentication.SetAuthCookie(user.Username, true);
            Session["User"] = user;

            // Redirect to startpage
            return RedirectToAction("Index", "Snippet");
        }

        public ActionResult Profile(string username, int? snippetsPage, int? favoritesPage) {
            var user = _userService.GetByUsernameForProfile(username);

            if (user == null)
                return View("NotFound", new NotFoundModel());

            var snippetService = new SnippetService();
            var model = new UserProfileModel(user);

            model.MySnippets = snippetService.GetAllPagedByUser(snippetsPage, user);
            model.MyFavorites = snippetService.GetPagedFavoritesByUser(favoritesPage, user);
            
            if (Request.IsAjaxRequest()) {
                if (snippetsPage.HasValue)
                    return PartialView("_SnippetList", model.MySnippets);
                if (favoritesPage.HasValue)
                    return PartialView("_SnippetList", model.MyFavorites);
            }

            return View(model);
        }

        [Authorize, ActionName("Edit"), ImportModelStateFromTempData]
        public ActionResult EditProfile(string username) {
            var user = _userService.GetByUsername(username);
            var loggedInUser = User as User;

            if (user == null)
                return View("NotFound", new NotFoundModel());

            if (loggedInUser == null || user.Username != loggedInUser.Username)
                return RedirectToAction("Profile", new {username});

            EditProfileModel model = new EditProfileModel(user);

            return View("EditProfile", model);
        }

        [HttpPost, ActionName("Edit")]
        public ActionResult EditProfile(string username, EditProfileModel model) {
            var user = _userService.GetByUsername(username);
            var loggedInUser = User as User;

            if (user == null)
                return View("NotFound", new NotFoundModel());

            if (loggedInUser == null || user.Username != loggedInUser.Username)
                return RedirectToAction("Profile", new { username });

            if (!ModelState.IsValid)
                return View("EditProfile", model);

            if (model.Password != null && model.ConfirmPassword != null)
                user.PasswordHashed = Hash.Make(model.Password);

            user.Email = model.Email;
            user.TwitterUsername = FixTwitterUsername(model.TwitterUsername);
            user.Website = FixWebsiteUrl(model.Website);
            
            _userService.Save();
            
            TempData["Message"] = "Your profile has been updated.";
            return RedirectToAction("Profile", new { username });
        }

        public ActionResult Logout() {
            FormsAuthentication.SignOut();
             
            return Redirect("/");
        }

        public ActionResult UsernameFree(string username) {
            return Json(!_userService.UsernameExists(username, null));
        }

        private ActionResult RedirectToLoginWithError(string message = "Invalid Username or Password") {
            ModelState.AddModelError("_form", message);
            return RedirectToAction("Login", "User", new { area = "" });
        }

        private string FixWebsiteUrl(string url) {
            if (url.IsNullOrEmpty())
                return null;

            if (!url.StartsWith("http"))
                url = "http://" + url;

            return url;
        }

        private string FixTwitterUsername(string username) {
            return !username.IsNullOrEmpty() ? username.Replace("@", "") : username;
        }
    }
}
